﻿using System.Net;
using ApiLib.AppStart;
using ApiLib.Models;
using ApiLib.Utils;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Http;

namespace ApiLib.Cloud.Common;

/// <summary>
/// 默认中间件
/// </summary>
public class MyCloudMiddleware
{
    private readonly RequestDelegate _next;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="next"></param>
    public MyCloudMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    public async Task InvokeAsync(HttpContext context)
    {
        // ...
        // context.Response.Headers.AccessControlAllowHeaders = "*";
        // context.Response.Headers.AccessControlAllowOrigin = "*";
        if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
        {
            try
            {
                // context.Response.Headers.AccessControlAllowOrigin = context.Request.Headers.AccessControlAllowOrigin;
                context.Response.Headers.AccessControlAllowOrigin = "*";
                context.Response.Headers.AccessControlAllowHeaders = context.Request.Headers.AccessControlAllowHeaders;
                context.Response.Headers.AccessControlAllowMethods = "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH";
                context.Response.Headers.AccessControlAllowCredentials = "true";
                if (context.Request.Method.Equals("OPTIONS"))
                {
                    // context.Response.StatusCode = StatusCodes.Status200OK;
                    // await Task.CompletedTask;
                    await _next(context);
                    return;
                }
            }
            catch (Exception e)
            {
                WebUtil.LogExp(e.Message);
            }

            /*context.Response.Headers.Add("Access-Control-Allow-Origin", context.Request.Headers["Origin"]);
            context.Response.Headers.Add("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH");
            context.Response.Headers.Add("Access-Control-Allow-Headers", context.Request.Headers["Access-Control-Request-Headers"]);
            context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");*/
        }

        var path = context.Request.Path.Value;
        if (path != null)
        {
            //路由校验：黑名单禁止访问
            if (IsBlack(path))
            {
                context.Response.StatusCode = 403;
                await context.Response.WriteAsync(BaseResponse<string>.Failed("禁止访问！").Serialize());
                await Task.CompletedTask;
                return;
            }

            //系统白名单校验
            if (SysRouteWhite(path) || IsUploads(path))
            {
                await _next(context);
                return;
            }

            //路由校验：非白名单需要认证
            if (!IsWhite(path))
            {
                var token = context.Request.Headers.Authorization.ToString();
                var auth = false;
                if (!string.IsNullOrEmpty(token))
                {
                    // token = token.Replace("Bearer ", "");
                    var baseUser = GlobalConfig.BaseAuthorization?.Authorization(context.Request);
                    if (baseUser != null)
                    {
                        auth = true;
                        context.Request.Headers["BaseUser"] = baseUser.GetSid();
                    }
                }

                if (!auth)
                {
                    context.Response.StatusCode = 401;
                    await context.Response.WriteAsync(BaseResponse<string>.Failed("需要身份认证！").Serialize());
                    await Task.CompletedTask;
                    return;
                }
            }

            //不需要转发
            if (path.StartsWith("/api/"))
            {
                // 调用下一个中间件
                await _next(context);
                return;
            }

            //转发请求
            var indexOf = path.IndexOf("/", 1, StringComparison.Ordinal);
            if (indexOf > 0) // 存在两个/，取中间进行路由
            {
                var route = path.SubstringJ(1, indexOf);
                var serviceInfos = CloudUtil.GetServiceInfo();
                /*var serviceInfo = serviceInfos.GetService(route);
                if (serviceInfo != null)
                {
                    try
                    {
                        serviceInfo.OnExecuting = true;
                        serviceInfo.VisitedAmount++;
                        var resource = path.Substring(indexOf);
                        await context.Forward(serviceInfo.Host + resource);
                        await Task.CompletedTask;
                        return;
                    }
                    catch (Exception e)
                    {
                        WebUtil.Error($"请求{path}转发到服务{serviceInfo.Name}失败");
                        WebUtil.Error(e.Message);
                    }
                    finally
                    {
                        serviceInfo.OnExecuting = false;
                    }
                }*/
                var serviceList = serviceInfos.GetServiceList(route);
                /*if (serviceList.IsNullOrEmpty())
                {
                    context.Response.StatusCode = 500;
                    await context.Response.WriteAsync(BaseResponse<string>.Failed("服务不存在或被禁用！").Serialize());
                    await Task.CompletedTask;
                    return;
                }*/
                if (!serviceList.IsNullOrEmpty())
                {
                    var resource = path.Substring(indexOf);
                    HttpResponseMessage? resp = null;
                    foreach (var serviceInfo in serviceList)
                    {
                        try
                        {
                            serviceInfo.OnExecuting = true;
                            serviceInfo.VisitedAmount++;
                            var response = await context.Request.Forward(serviceInfo.Host + resource);
                            if (response.StatusCode != HttpStatusCode.NotFound)
                            {
                                await context.CopyFrom(response);
                                await Task.CompletedTask;
                                return;
                            }

                            resp ??= response;
                        }
                        catch (Exception e)
                        {
                            WebUtil.Error($"请求{path}转发到服务{serviceInfo.Name}失败", e);
                        }
                        finally
                        {
                            serviceInfo.OnExecuting = false;
                        }
                    }

                    if (resp != null)
                    {
                        await context.CopyFrom(resp);
                        await Task.CompletedTask;
                        return;
                    }

                    context.Response.StatusCode = 500;
                    await context.Response.WriteAsync(BaseResponse<string>.Failed("全部处理失败！").Serialize());
                    await Task.CompletedTask;
                    return;
                }
            }
        }

        // 调用下一个中间件
        await _next(context);
    }

    /// <summary>
    /// 系统路由白名单
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private bool SysRouteWhite(string path)
    {
        foreach (var route in GlobalConfig.RouteWhiteList)
        {
            if (IsMatch(route, path))
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 系统路由白名单
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private static bool IsBlack(string path)
    {
        var cloudRoutes = CloudUtil.GetRoute();
        if (cloudRoutes.IsNullOrEmpty())
        {
            return false;
        }

        var routes = cloudRoutes.Where(route => route.IsBlack);
        foreach (var route in routes)
        {
            if (IsMatch(route.Path, path))
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 是白名单
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private static bool IsWhite(string path)
    {
        var cloudRoutes = CloudUtil.GetRoute();
        if (cloudRoutes.IsNullOrEmpty())
        {
            return false;
        }

        var routes = cloudRoutes.Where(route => route.IsWhite);
        foreach (var route in routes)
        {
            if (IsMatch(route.Path, path))
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 是否匹配
    /// </summary>
    /// <param name="route"></param>
    /// <param name="path"></param>
    /// <returns></returns>
    private static bool IsMatch(string route, string path)
    {
        if (route.EndsWith("*"))
        {
            var route2 = route.Substring(0, route.Length - 1);
            if (!route2.Contains("*") && path.StartsWith(route2))
            {
                return true;
            }
        }
        else if (route.StartsWith("*"))
        {
            var route2 = route.Substring(1);
            if (!route2.Contains("*") && path.EndsWith(route2))
            {
                return true;
            }
        }
        else
        {
            if (route == path)
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 是上传文件
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private bool IsUploads(string path)
    {
        return path.StartsWith("/" + GlobalConfig.UploadPath + "/");
    }
}